using System;
using System.Collections;
using System.Collections.Generic;

using OpenTK;
using OpenTK.OpenGL;
using OpenTK.OpenGL.Enums;
using OpenTK.Fonts;
using OpenTK.Math;
using OpenTK.Input;
using OpenTK.Platform;

namespace Gamadus.Engine
{
public class InputMgr : SingletonManager<InputMgr>
{
	List<int> KeyPress = new List<int>();
	List<int> KeyPressed = new List<int>();
	List<int> KeyRelease = new List<int>();
	
	Dictionary<OpenTK.Input.Key,int> KeyCodes = new Dictionary<Key,int>();
	
	Hashtable MousePress = new Hashtable();
	Hashtable MousePressed = new Hashtable();
	Hashtable MouseRelease = new Hashtable();
	
	public void Init()
	{
		SetKeyCodes();
	}
	
	void SetKeyCodes()
	{
		//GML.Builtin.vk_enter -> Key.KeypadEnter|Key.Return
		//GML.Builtin.vk_alt -> Key.RightAlt|Key.LeftAlt
		//GML.Builtin.vk_anykey
		//GML.Builtin.vk_control -> Key.RightControl|Key.LeftControl
		//GML.Builtin.vk_nokey
		//GML.Builtin.vk_shift -> Key.RightShift|Key.LeftShift
		
		KeyCodes.Add(Key.KeypadAdd, (int)GML.Builtin.vk_add.val);
		KeyCodes.Add(Key.BackSpace, (int)GML.Builtin.vk_backspace.val);
		KeyCodes.Add(Key.KeypadDecimal, (int)GML.Builtin.vk_decimal.val);
		KeyCodes.Add(Key.Delete, (int)GML.Builtin.vk_delete.val);
		KeyCodes.Add(Key.KeypadDivide, (int)GML.Builtin.vk_divide.val);
		KeyCodes.Add(Key.Down, (int)GML.Builtin.vk_down.val);
		KeyCodes.Add(Key.End, (int)GML.Builtin.vk_end.val);
		KeyCodes.Add(Key.Escape, (int)GML.Builtin.vk_escape.val);
		KeyCodes.Add(Key.F1, (int)GML.Builtin.vk_f1.val);
		KeyCodes.Add(Key.F2, (int)GML.Builtin.vk_f2.val);
		KeyCodes.Add(Key.F3, (int)GML.Builtin.vk_f3.val);
		KeyCodes.Add(Key.F4, (int)GML.Builtin.vk_f4.val);
		KeyCodes.Add(Key.F5, (int)GML.Builtin.vk_f5.val);
		KeyCodes.Add(Key.F6, (int)GML.Builtin.vk_f6.val);
		KeyCodes.Add(Key.F7, (int)GML.Builtin.vk_f7.val);
		KeyCodes.Add(Key.F8, (int)GML.Builtin.vk_f8.val);
		KeyCodes.Add(Key.F9, (int)GML.Builtin.vk_f9.val);
		KeyCodes.Add(Key.F10, (int)GML.Builtin.vk_f10.val);
		KeyCodes.Add(Key.F11, (int)GML.Builtin.vk_f11.val);
		KeyCodes.Add(Key.F12, (int)GML.Builtin.vk_f12.val);
		KeyCodes.Add(Key.Home, (int)GML.Builtin.vk_home.val);
		KeyCodes.Add(Key.Insert, (int)GML.Builtin.vk_insert.val);
		KeyCodes.Add(Key.AltLeft, (int)GML.Builtin.vk_lalt.val);
		KeyCodes.Add(Key.ControlLeft, (int)GML.Builtin.vk_lcontrol.val);
		KeyCodes.Add(Key.Left, (int)GML.Builtin.vk_left.val);
		KeyCodes.Add(Key.ShiftLeft, (int)GML.Builtin.vk_lshift.val);
		KeyCodes.Add(Key.KeypadMultiply, (int)GML.Builtin.vk_multiply.val);
		KeyCodes.Add(Key.Keypad0, (int)GML.Builtin.vk_numpad0.val);
		KeyCodes.Add(Key.Keypad1, (int)GML.Builtin.vk_numpad1.val);
		KeyCodes.Add(Key.Keypad2, (int)GML.Builtin.vk_numpad2.val);
		KeyCodes.Add(Key.Keypad3, (int)GML.Builtin.vk_numpad3.val);
		KeyCodes.Add(Key.Keypad4, (int)GML.Builtin.vk_numpad4.val);
		KeyCodes.Add(Key.Keypad5, (int)GML.Builtin.vk_numpad5.val);
		KeyCodes.Add(Key.Keypad6, (int)GML.Builtin.vk_numpad6.val);
		KeyCodes.Add(Key.Keypad7, (int)GML.Builtin.vk_numpad7.val);
		KeyCodes.Add(Key.Keypad8, (int)GML.Builtin.vk_numpad8.val);
		KeyCodes.Add(Key.Keypad9, (int)GML.Builtin.vk_numpad9.val);
		KeyCodes.Add(Key.PageDown, (int)GML.Builtin.vk_pagedown.val);
		KeyCodes.Add(Key.PageUp, (int)GML.Builtin.vk_pageup.val);
		KeyCodes.Add(Key.Pause, (int)GML.Builtin.vk_pause.val);
		KeyCodes.Add(Key.PrintScreen, (int)GML.Builtin.vk_printscreen.val);
		KeyCodes.Add(Key.AltRight, (int)GML.Builtin.vk_ralt.val);
		//KeyCodes.Add(Key.Mode, (int)GML.Builtin.vk_ralt.val);
		KeyCodes.Add(Key.Right, (int)GML.Builtin.vk_right.val);
		KeyCodes.Add(Key.ShiftRight, (int)GML.Builtin.vk_rshift.val);
		KeyCodes.Add(Key.ControlRight, (int)GML.Builtin.vk_rcontrol.val);
		KeyCodes.Add(Key.Space, (int)GML.Builtin.vk_space.val);
		KeyCodes.Add(Key.KeypadSubtract, (int)GML.Builtin.vk_subtract.val);
		KeyCodes.Add(Key.Tab, (int)GML.Builtin.vk_tab.val);
		KeyCodes.Add(Key.Up, (int)GML.Builtin.vk_up.val);
		KeyCodes.Add(Key.Enter, (int)GML.Builtin.vk_enter.val);
	}
	
	void AddKey(Key key, List<int> list)
	{
		int code = KeyCodes[key];
		list.Add(code);
		if(code == (int)GML.Builtin.vk_lalt.val || code == (int)GML.Builtin.vk_ralt.val)
			list.Add((int)GML.Builtin.vk_alt.val);
		else if(code == (int)GML.Builtin.vk_lcontrol.val || code == (int)GML.Builtin.vk_rcontrol.val)
			list.Add((int)GML.Builtin.vk_control.val);
		else if(code == (int)GML.Builtin.vk_lshift.val || code == (int)GML.Builtin.vk_rshift.val)
			list.Add((int)GML.Builtin.vk_shift.val);
	}
	void RemoveKey(Key key, List<int> list)
	{
		int code = KeyCodes[key];
		if(list.Contains(code))
			list.Remove(code);
		if(list.Contains((int)GML.Builtin.vk_alt.val) && (code == (int)GML.Builtin.vk_lalt.val || code == (int)GML.Builtin.vk_ralt.val))
		{
			list.Remove((int)GML.Builtin.vk_alt.val);
		}
		else if(list.Contains((int)GML.Builtin.vk_control.val) && (code == (int)GML.Builtin.vk_lcontrol.val || code == (int)GML.Builtin.vk_rcontrol.val))
		{
			list.Remove((int)GML.Builtin.vk_control.val);
		}
		else if(list.Contains((int)GML.Builtin.vk_shift.val) && (code == (int)GML.Builtin.vk_lshift.val || code == (int)GML.Builtin.vk_rshift.val))
		{
			list.Remove((int)GML.Builtin.vk_shift.val);
		}
	}
	/// <summary>
	/// This is called when the close button of the game window is pressed.
	/// Checks whether close button is allowed by Game Settings (AllowCloseButton) and Quit
	/// </summary>
	public void Events_Quit(object sender, EventArgs e)
	{
		//TODO: Call Event
		//TODO: This has to call the game-end events
		if((bool)GamadusEngine.Instance.GameSettings["AllowCloseButton"])
	  		WindowMgr.Instance.Exit();
	}
	public void Events_MouseDown(MouseDevice sender, MouseButton button)
	{
		MousePress.Add(button, true);
		MousePressed.Add(button, true);
	}
	public void Events_MouseUp(MouseDevice sender, MouseButton button)
	{
		if(MousePressed.ContainsKey(button))
        		MousePressed.Remove(button);
        	
        MouseRelease.Add(button,true);
	}
	public void Events_KeyboardDown(KeyboardDevice sender, Key key)
    {
    	AddKey(key, KeyPress);
    	AddKey(key, KeyPressed);
    	
        switch (key)
        {
			case Key.F4:
                if((bool)GamadusEngine.Instance.GameSettings["AllowF4"])
                {
                	WindowMgr.Instance.Fullscreen=!WindowMgr.Instance.Fullscreen;
                }
                break;
            case Key.Escape:
                //TODO: This has to call the game-end events
                if((bool)GamadusEngine.Instance.GameSettings["AllowESC"])
                	WindowMgr.Instance.Exit();
                break;
        }
    }

        public void Events_KeyboardUp(KeyboardDevice sender, Key key)
        {
        	RemoveKey(key, KeyPressed);
        	AddKey(key, KeyRelease);
        }
        public void UpdateKeys()
        {
        	KeyPress.Clear();
        	KeyRelease.Clear();
        	MousePress.Clear();
        	MouseRelease.Clear();
        }
        //KEYBOARD//
        public bool KeyboardCheck(int k)
        {
        	
        	if(k == GML.Builtin.vk_anykey)
        		return KeyPressed.Count > 0;
        	else if(k == GML.Builtin.vk_nokey)
        		return KeyPressed.Count == 0;
        	else
        		return KeyPressed.Contains(k);
        }
        public bool KeyboardCheckPressed(int k)
        {
        	if(k == GML.Builtin.vk_anykey)
        		return KeyPress.Count > 0;
        	else if(k == GML.Builtin.vk_nokey)
        		return KeyPress.Count == 0;
        	else
        		return KeyPress.Contains(k);
        }
        public bool KeyboardCheckReleased(int k)
        {
        	if(k == GML.Builtin.vk_anykey)
        		return KeyRelease.Count > 0;
        	else if(k == GML.Builtin.vk_nokey)
        		return KeyRelease.Count == 0;
        	else
        		return KeyRelease.Contains(k);
        }
        
        //MOUSE//
        public bool MouseCheckPressed(MouseButton mb)
        {
        	return MousePress.ContainsKey(mb);
        }
        public bool MouseCheckPressed(bool mb)
        {
        	if(mb)
        		return (MousePress.Count>0);
        	else
        		return (MousePress.Count<=0);
        }
        public bool MouseCheckReleased(MouseButton mb)
        {
        	return MouseRelease.ContainsKey(mb);
        }
        public bool MouseCheckReleased(bool mb)
        {
        	if(mb)
        		return (MouseRelease.Count>0);
        	else
        		return (MouseRelease.Count<=0);
        }
        public bool MouseCheck(MouseButton mb)
        {
        	return MousePressed.ContainsKey(mb);
        }
        public bool MouseCheck(bool mb)
        {
        	if(mb)
        		return (MousePressed.Count>0);
        	else
        		return (MousePressed.Count<=0);
        }
}
}
